package com.apestech.framework.util;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Locale;

/**
 * 与格式化有关的转义 涉及：支持国际化数值类（金额、普通数值、百分比、千分比）<br>
 * JAVA原生Math类下提供的向上取整、向下取整、四舍五入方法在计算负数规则时有问题，建议使用MathUtil下对应同名方法，所有有提供小数位入口，输入小于等于0的数，均会按照取整数方式解析<br>
 * DecimalFormat的四舍五入算法，负数计算规则同JAVA原生Math的round函数，如果需要做格式化字串输出操作，建议统一走该类下对应数值或者金额format开头方法<br>
 * @author hupo
 *
 */
public class FormatUtil extends StringUtil {
	
	/**
	 * 获取数字格式化字串
	 * @param scale 小数位数
	 * @param prefix 前缀字串
	 * @return
	 */
	private static String getNumberPattern(int scale,String prefix){
		String pattern=prefix;
		if(scale>0){
			pattern=pattern+".";
			for(int i=1; i<=scale; i++){
				pattern=pattern+"0";
			}
		}
		return pattern;
	}
	
	/**
	 * 执行数值格式化
	 * @param pattern
	 * @param d
	 * @param l
	 * @return
	 */
	private static String formatNumber(String pattern, double d, Locale l){
		DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(l);
	    df.applyPattern(pattern);
	    return df.format(d);
	}
	
	/**
	 * 执行数值格式化
	 * @param pattern
	 * @param d
	 * @return
	 */
	private static String formatNumber(String pattern, double d){
		return formatNumber(pattern, d, Locale.getDefault());
	}
	
	/**
	 * 根据设定小数位，将数值进行向下取值
	 * @param d 数字
	 * @param scale 小数位
	 * @return
	 */
	public static String formatNumberFloor(double d, int scale){
		String pattern=getNumberPattern(scale,"#");
		return formatNumber(pattern, MathUtil.floor(d,scale));
	}
	
	/**
	 * 根据设定小数位，将数值进行向上取值
	 * @param d 数字
	 * @param scale 小数位
	 * @return
	 */
	public static String formatNumberCeil(double d, int scale){
		String pattern=getNumberPattern(scale,"#");
		return formatNumber(pattern, MathUtil.ceil(d,scale));
	}
	
	/**
	 * 根据设定小数位，将数据进行四舍五入
	 * @param d 数字
	 * @param scale 小数位
	 * @return
	 */
	public static String formatNumberRound(double d, int scale){
		String pattern=getNumberPattern(scale,"#");
		return formatNumber(pattern, MathUtil.round(d,scale));
	}
	
	/**
	 * 获取百分比Pattern
	 * @param scale
	 * @return
	 */
	private static String getPercentPattern(int scale){
		if(scale<0){
			scale=0;
		}
		String pattern=getNumberPattern(scale,"#");
		pattern=pattern+"%";
		return pattern;
	}

	public static String formatNumberPercent(double d, int scale){
		String pattern=getPercentPattern(scale);
		return formatNumber(pattern, d*100);
	}
	
	/**
	 * 根据设定小数位，将数值进行向下取值，以百分比方式显示
	 * @param d 数字
	 * @param scale 小数位
	 * @return
	 */
	public static String formatNumberPercentFloor(double d, int scale){
		String pattern=getPercentPattern(scale);
		return formatNumber(pattern, MathUtil.floor(d,scale+2));
	}
	
	/**
	 * 根据2位小数位，将数值进行向下取值，以百分比方式显示
	 * @param d 数字
	 * @return
	 */
	public static String formatNumberPercentFloor(double d){
		return formatNumberPercentFloor(d,2);
	}
	
	/**
	 * 根据设定小数位，将数值进行向上取值，以百分比方式显示
	 * @param d 数字
	 * @param scale 小数位
	 * @return
	 */
	public static String formatNumberPercentCeil(double d, int scale){
		String pattern=getPercentPattern(scale);
		return formatNumber(pattern, MathUtil.ceil(d,scale+2));
	}
	
	/**
	 * 根据2位小数位，将数值进行向上取值，以百分比方式显示
	 * @param d 数字
	 * @return
	 */
	public static String formatNumberPercentCeil(double d){
		return formatNumberPercentCeil(d,2);
	}
	
	/**
	 * 根据设定小数位，将数据进行四舍五入，以百分比方式显示
	 * @param d 数字
	 * @param scale 小数位
	 * @return
	 */
	public static String formatNumberPercentRound(double d, int scale){
		String pattern=getPercentPattern(scale);
		return formatNumber(pattern, MathUtil.round(d,scale+2));
	}
	
	/**
	 * 根据2位小数位，将数据进行四舍五入，以百分比方式显示
	 * @param d 数字
	 * @return
	 */
	public static String formatNumberPercentRound(double d){
		return formatNumberPercentRound(d,2);
	}
	
	/**
	 * 获取千分比Pattern
	 * @param scale
	 * @return
	 */
	private static String getPermillagePattern(int scale){
		if(scale<0){
			scale=0;
		}
		String pattern=getNumberPattern(scale,"");
		if("".equals(pattern)){
			pattern=pattern+"#";
		}
		pattern=pattern+"‰";
		return pattern;
	}

	public static String formatNumberPermillage(double d, int scale){
		String pattern=getPermillagePattern(scale);
		return formatNumber(pattern, d*1000);
	}
	
	/**
	 * 根据设定小数位，将数值进行向下取值，以千分比方式显示
	 * @param d 数字
	 * @param scale 小数位
	 * @return
	 */
	public static String formatNumberPermillageFloor(double d, int scale){
		String pattern=getPermillagePattern(scale);
		return formatNumber(pattern, MathUtil.floor(d,scale+3));
	}
	
	/**
	 * 根据2位小数位，将数值进行向下取值，以千分比方式显示
	 * @param d 数字
	 * @return
	 */
	public static String formatNumberPermillageFloor(double d){
		return formatNumberPermillageFloor(d,2);
	}
	
	/**
	 * 根据设定小数位，将数值进行向上取值，以千分比方式显示
	 * @param d 数字
	 * @param scale 小数位
	 * @return
	 */
	public static String formatNumberPermillageCeil(double d, int scale){
		String pattern=getPermillagePattern(scale);
		return formatNumber(pattern, MathUtil.ceil(d,scale+3));
	}
	
	/**
	 * 根据2位小数位，将数值进行向上取值，以千分比方式显示
	 * @param d 数字
	 * @return
	 */
	public static String formatNumberPermillageCeil(double d){
		return formatNumberPermillageCeil(d,2);
	}
	
	/**
	 * 根据设定小数位，将数据进行四舍五入，以千分比方式显示
	 * @param d 数字
	 * @param scale 小数位
	 * @return
	 */
	public static String formatNumberPermillageRound(double d, int scale){
		String pattern=getPermillagePattern(scale);
		return formatNumber(pattern, MathUtil.round(d,scale+3));
	}
	
	/**
	 * 根据2位小数位，将数据进行四舍五入，以千分比方式显示
	 * @param d 数字
	 * @return
	 */
	public static String formatNumberPermillageRound(double d){
		return formatNumberPermillageRound(d,2);
	}
	
	/**
	 * 获取各国币种简写
	 * @param locale
	 * @return
	 */
	public static String getCurrencyShorthand(Locale locale){
		if(locale.equals(Locale.CHINESE) || locale.equals(Locale.CHINA) || locale.equals(Locale.SIMPLIFIED_CHINESE) || locale.equals(Locale.PRC) ){
			return "CNY";  //CNY（ChiNese Yuan）人民币  
		} else if(locale.equals(Locale.ENGLISH) || locale.equals(Locale.UK) ){
			return "GBP";  //GBP（Great Britain Pound）英镑
		} else if(locale.equals(Locale.CANADA) || locale.equals(Locale.CANADA_FRENCH) ){
			return "CAD";  //CAD（CAnadian Dollar）加拿大元 
		} else if(locale.equals(Locale.FRANCE) || locale.equals(Locale.FRENCH) ){
			return "FRF";  //FRF（FRench Franc）法国法郎  EUR
		} else if(locale.equals(Locale.GERMAN) || locale.equals(Locale.GERMANY) ){
			return "DEM";  //DEM（德文 DEutsche M ark）德国马克 EUR
		} else if(locale.equals(Locale.JAPANESE) || locale.equals(Locale.JAPAN) ){
			return "JPY";  //JPY（JaPanese Yen）日元
		} else if(locale.equals(Locale.KOREA) || locale.equals(Locale.KOREAN) ){
			return "KRW";  //KRW（KRW-Korea Won）韩国元
		} else if(locale.equals(Locale.TAIWAN)){
			return "NTD";  //NTD(New TaiWan Dollar)新台币
		} else if(locale.equals(Locale.TRADITIONAL_CHINESE)){
			return "HKD";  //HKD（HongKong Dollars）
		} else if(locale.equals(Locale.US)){
			return "USD";  //USD（United States Dollar）美元
		} else if(locale.equals(Locale.ITALIAN) || locale.equals(Locale.ITALY) ){
			return "EUR";
		}
        return "";
	}

	/**
	 * 结合getCurrencyShorthand调用，获取各国货币符号
	 * @param currencyShorthand
	 * @return
	 */
	public static String getCurrencySymbol(String currencyShorthand){
		if("CNY".equals(currencyShorthand)){
			return "¥";
		} else if("GBP".equals(currencyShorthand)){
			return "￡";
		} else if("CAD".equals(currencyShorthand)){
			return "C$";
		} else if("FRF".equals(currencyShorthand)){
			return "₣";
		} else if("DEM".equals(currencyShorthand)){
			return "DM";
		} else if("JPY".equals(currencyShorthand)){
			return "J¥";
		} else if("KRW".equals(currencyShorthand)){
			return "₩";
		} else if("TWD".equals(currencyShorthand)){
			return "NT$";
		} else if("HKD".equals(currencyShorthand)){
			return "HK$";
		} else if("GBP".equals(currencyShorthand)){
			return "HK$";
		} else if("USD".equals(currencyShorthand)){
			return "＄";
		} else if("EUR".equals(currencyShorthand)){
			return "€";
		}
		return "";
	}
	
	/**
	 * 获取格式化字串格式
	 * @param type
	 * @return
	 */
	public static String getPattern(String type){
		String text=type;
		switch(type){
			case "0":         //取一位整数
				break; 
			case "0.00":      //取一位整数和两位小数
				break;
			case "00.000":    //取两位整数和三位小数，整数不足部分以0填补。
				break;
			case "#":         //取所有整数部分
				break;
			case "#.##%":     //以百分比方式计数，并取两位小数
				break;
			case "#.#####E0": //显示为科学计数法，并取五位小数
				break;				
			case "00.####E0": //显示为两位整数的科学计数法，并取四位小数
				break;
			case ",###":      //整数部分每三位以逗号进行分隔。
				break;
			case "#,###.00":  //整数部分每三位以逗号进行分隔,保留二位小数。
				break;
			case "###.0#":    //表示输出的数值可以保留一位或两位小数；
				break;
			case "%":         //以百分比方式计数，并取两位小数
				text="#.##%";
				break;
			default:
				text=type;
			    break;
		}
		return text;
	}
	
	/**
	   * 格式化货币
	   * @param d double
	   * @param pattern String "\u00A4#,###.00" :显示为 ￥1，234，234.10
	   * @param l Locale
	   * @return String
	   * @throws Exception 
	   */
	public static String formatCurrency(double d,String pattern,Locale l) throws Exception{
	    String s = "";
	    try{
	      DecimalFormat nf = (DecimalFormat) NumberFormat.getCurrencyInstance(l);
	      nf.applyPattern(pattern);
	      s = nf.format(d);
	    }catch(Exception e){
	    	throw new Exception(getMessage("FormatUtil_errorformatNumber","错误的格式化数值"));
	    }
	    return s;
	}
	
	/**
	 * 根据默认区域，格式化货币
	 * @param d
	 * @param pattern
	 * @return
	 * @throws Exception
	 */
	public static String formatCurrency(double d,String pattern) throws Exception{
		return formatCurrency(d,pattern,Locale.getDefault());
	}
	
	/**
	 * 返回区域货币符号方式，格式化货币 
	 * @param d
	 * @param pattern
	 * @param l
	 * @return
	 * @throws Exception
	 */
	public static String formatCurrencySymbol(double d,String pattern,Locale l) throws Exception{
		if(d==0) return "0";
		String t=formatCurrency(d,pattern,l);
		if(leftStr(t,1).equals(".")){
			t="0"+t;
		}
		return getCurrencySymbol(getCurrencyShorthand(l))+t;
	}

	/**
	 * 返回区域货币符号方式，根据默认区域，格式化货币
	 * @param d
	 * @param pattern
	 * @return
	 * @throws Exception
	 */
	public static String formatCurrencySymbol(double d,String pattern) throws Exception{
		if(d==0) return "0";
		String t=formatCurrency(d,pattern,Locale.getDefault());
		if(leftStr(t,1).equals(".")){
			t="0"+t;
		}
		return getCurrencySymbol(getCurrencyShorthand(Locale.getDefault()))+t;
	}
	
	/**
	 * 根据设定小数位，将数值向下取值格式化金额类型字串
	 * @param d
	 * @param scale
	 * @return
	 * @throws Exception
	 */
	public static String formatCurrencyFloor(double d,int scale,Locale l) throws Exception{
		String pattern=getNumberPattern(scale,"#,###");
		return formatCurrency(MathUtil.floor(d,scale),pattern,l);
	}

	/**
	 * 根据设定小数位，将数值向下取值格式化金额类型字串
	 * @param d
	 * @param scale
	 * @return
	 * @throws Exception
	 */
	public static String formatCurrencyFloor(double d,int scale) throws Exception{
		String pattern=getNumberPattern(scale,"#,###");
		return formatCurrency(MathUtil.floor(d,scale),pattern,Locale.getDefault());
	}

	/**
	 * 根据设定小数位，将数值向下取值格式化带符号金额类型字串
	 * @param d
	 * @param scale
	 * @param l
	 * @return
	 * @throws Exception
	 */
	public static String formatCurrencySymbolFloor(double d,int scale,Locale l) throws Exception{
		if(d==0) return "0";
		String t=formatCurrencyFloor(d,scale);
		if(leftStr(t,1).equals(".")){
			t="0"+t;
		}
		return getCurrencySymbol(getCurrencyShorthand(l))+t;
	}
	
	/**
	 * 根据设定小数位，将数值向下取值格式化带符号金额类型字串
	 * @param d
	 * @param scale
	 * @return
	 * @throws Exception
	 */
	public static String formatCurrencySymbolFloor(double d,int scale) throws Exception{
		if(d==0) return "0";
		String t=formatCurrencyFloor(d,scale);
		if(leftStr(t,1).equals(".")){
			t="0"+t;
		}
		return getCurrencySymbol(getCurrencyShorthand(Locale.getDefault()))+t;
	}

	public static String formatCurrency(double d,int scale,Locale l) throws Exception{
		String pattern=getNumberPattern(scale,"#,###");
		return formatCurrency(d,pattern,l);
	}
	
	/**
	 * 根据设定小数位，将数值向上取值格式化金额类型字串
	 * @param d
	 * @param scale
	 * @return
	 * @throws Exception
	 */
	public static String formatCurrencyCeil(double d,int scale,Locale l) throws Exception{
		String pattern=getNumberPattern(scale,"#,###");
		return formatCurrency(MathUtil.ceil(d,scale),pattern,l);
	}

	/**
	 * 根据设定小数位，将数值向上取值格式化金额类型字串
	 * @param d
	 * @param scale
	 * @return
	 * @throws Exception
	 */
	public static String formatCurrencyCeil(double d,int scale) throws Exception{
		String pattern=getNumberPattern(scale,"#,###");
		return formatCurrency(MathUtil.ceil(d,scale),pattern,Locale.getDefault());
	}
	
	/**
	 * 根据设定小数位，将数值向上取值格式化带符号金额类型字串
	 * @param d
	 * @param scale
	 * @return
	 * @throws Exception
	 */
	public static String formatCurrencySymbolCeil(double d,int scale,Locale l) throws Exception{
		if(d==0) return "0";
		String t=formatCurrencyCeil(d,scale);
		if(leftStr(t,1).equals(".")){
			t="0"+t;
		}
		return getCurrencySymbol(getCurrencyShorthand(l))+t;
	}

	/**
	 * 根据设定小数位，将数值向上取值格式化带符号金额类型字串
	 * @param d
	 * @param scale
	 * @return
	 * @throws Exception
	 */
	public static String formatCurrencySymbolCeil(double d,int scale) throws Exception{
		if(d==0) return "0";
		String t=formatCurrencyCeil(d,scale);
		if(leftStr(t,1).equals(".")){
			t="0"+t;
		}
		return getCurrencySymbol(getCurrencyShorthand(Locale.getDefault()))+t;
	}
	
	/**
	 * 根据设定小数位，将数值四舍五入格式化金额类型字串
	 * @param d
	 * @param scale
	 * @return
	 * @throws Exception
	 */
	public static String formatCurrencyRound(double d,int scale,Locale l) throws Exception{
		String pattern=getNumberPattern(scale,"#,###");
		return formatCurrency(MathUtil.round(d,scale),pattern,l);
	}

	/**
	 * 根据设定小数位，将数值四舍五入格式化金额类型字串
	 * @param d
	 * @param scale
	 * @return
	 * @throws Exception
	 */
	public static String formatCurrencyRound(double d,int scale) throws Exception{
		String pattern=getNumberPattern(scale,"#,###");
		return formatCurrency(MathUtil.round(d,scale),pattern,Locale.getDefault());
	}

	public static String formatCurrencySymbol(double d, Locale l) throws Exception{
		if(d==0) return "0";
		return getCurrencySymbol(getCurrencyShorthand(l))+d;
	}
	
	/**
	 * 根据设定小数位，将数值四舍五入带符号金额类型字串
	 * @param d
	 * @param scale
	 * @return
	 * @throws Exception
	 */
	public static String formatCurrencySymbolRound(double d,int scale,Locale l) throws Exception{
		if(d==0) return "0";
		String t=formatCurrencyRound(d,scale);
		if(leftStr(t,1).equals(".")){
			t="0"+t;
		}
		return getCurrencySymbol(getCurrencyShorthand(l))+t;
	}

	/**
	 * 根据设定小数位，将数值四舍五入带符号金额类型字串
	 * @param d
	 * @param scale
	 * @return
	 * @throws Exception
	 */
	public static String formatCurrencySymbolRound(double d,int scale) throws Exception{
		if(d==0) return "0";
		String t=formatCurrencyRound(d,scale);
		if(leftStr(t,1).equals(".")){
			t="0"+t;
		}
		return getCurrencySymbol(getCurrencyShorthand(Locale.getDefault()))+t;
	}

	public static String getCurrencyPattern(int scale, Locale l){
		String pattern=getNumberPattern(scale,"#,###");
		DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(l);
		df.applyPattern(pattern);
		return df.toLocalizedPattern();
	}

	public static String getNumPattern(int scale, Locale l){
		String pattern=getNumberPattern(scale,"#");
		DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(l);
		df.applyPattern(pattern);
		return df.toLocalizedPattern();
	}

	public static String getPercentPattern(int scale, Locale l){
		String pattern=getPercentPattern(scale);
		DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(l);
		df.applyPattern(pattern);
		return df.toLocalizedPattern();
	}

	public static String getPermillagePattern(int scale, Locale l){
		String pattern=getPermillagePattern(scale);
		DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(l);
		df.applyPattern(pattern);
		return df.toLocalizedPattern();
	}

}
